﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using SimpleIR;
using System.Diagnostics.Contracts;

namespace RgnAnalyzer.Domain
{
	/// <summary>
	/// Abstract class representing all the types of local/global variable storage type locations we can have:
	/// (1) Pointers
	/// (2) References
	/// (3) Primitive values (integers, floating point).
	/// (4) Structs
	/// </summary>
	internal sealed class AHomeLocation : ALocation
	{
		/// <summary>
		/// True if this location represents a global static field.
		/// </summary>
		internal readonly bool IsGlobalLocation;

		/// <summary>
		/// If this is a numeric type this is the value
		/// </summary>
		private ZeroOne.Value m_numval;

		/// <summary>
		/// If this is a reference this is the value.
		/// </summary>
		private AReference m_refval;

		private AHomeLocation(IRType loctype, int address, bool isglobal, int[] identity, EscapeSiteInfo[] esclocinfo, List<UseModInfo> uml, ZeroOne.Value mval, AReference rval, APtrValueMap cval)
			: base(address, identity, esclocinfo, cval, uml, loctype)
		{
			this.IsGlobalLocation = isglobal;

			this.m_numval = mval;
			this.m_refval = rval;
		}

		/// <summary>
		/// Allocate a new home location containing a numeric typed value.
		/// </summary>
		internal AHomeLocation(IRNumericType loctype, int address, bool isglobal, ZeroOne.Value mval, int line)
			: this(loctype, address, isglobal, ALocation.EmptyIdentity, new EscapeSiteInfo[1], new List<UseModInfo>(), mval, default(AReference), default(APtrValueMap))
		{
			UseModInfo.MarkUMI(this.m_uml, true, false, false, true, line, IRBasicAccessPath.EmptyAccessPath);
			this.m_escapelines[0] = new EscapeSiteInfo(line, line, line);
		}

		/// <summary>
		/// Allocate a new home location containing an enum typed value.
		/// </summary>
		internal AHomeLocation(IREnumType loctype, int address, bool isglobal, ZeroOne.Value mval, int line)
			: this(loctype, address, isglobal, ALocation.EmptyIdentity, new EscapeSiteInfo[1], new List<UseModInfo>(), mval, default(AReference), default(APtrValueMap))
		{
			UseModInfo.MarkUMI(this.m_uml, true, false, false, true, line, IRBasicAccessPath.EmptyAccessPath);
			this.m_escapelines[0] = new EscapeSiteInfo(line, line, line);
		}

		/// <summary>
		/// Allocate new home location containing a reference typed value.
		/// </summary>
		internal AHomeLocation(IRReferenceType loctype, int address, bool isglobal, AReference rval, int line)
			: this(loctype, address, isglobal, ALocation.EmptyIdentity, new EscapeSiteInfo[1], new List<UseModInfo>(), ZeroOne.Value.Zero, rval, default(APtrValueMap))
		{
			UseModInfo.MarkUMI(this.m_uml, true, false, false, true, line, IRBasicAccessPath.EmptyAccessPath);
			this.m_escapelines[0] = new EscapeSiteInfo(line, line, line);
		}

		/// <summary>
		/// Allocate a new home location containing a pointer typed value.
		/// </summary>
		internal AHomeLocation(IRPtrType loctype, int address, bool isglobal, APtrValueMap sval, int line)
			: this(loctype, address, isglobal, ALocation.EmptyIdentity, new EscapeSiteInfo[1], new List<UseModInfo>(), ZeroOne.Value.Zero, default(AReference), sval)
		{
			UseModInfo.MarkUMI(this.m_uml, true, false, false, true, line, IRBasicAccessPath.EmptyAccessPath);
			this.m_escapelines[0] = new EscapeSiteInfo(line, line, line);
		}

		/// <summary>
		/// Allocate a new home location containing a struct typed value.
		/// </summary>
		internal AHomeLocation(IRStructType loctype, int address, bool isglobal, APtrValueMap sval, int line)
			: this(loctype, address, isglobal, ALocation.EmptyIdentity, new EscapeSiteInfo[1], new List<UseModInfo>(), ZeroOne.Value.Zero, default(AReference), sval)
		{
			UseModInfo.MarkUMIAtStructInitialization(loctype, this.m_uml, line);
			this.m_escapelines[0] = new EscapeSiteInfo(line, line, line);
		}

		internal override ALocation CopyLocation()
		{
			int[] ida = (this.m_identities == EmptyIdentity ? EmptyIdentity : (int[])this.m_identities.Clone());
			EscapeSiteInfo[] fli = (this.m_escapelines == EmptyAllocLines ? ALocation.EmptyAllocLines : (EscapeSiteInfo[])this.m_escapelines.Clone());
			List<UseModInfo> umv = new List<UseModInfo>(this.m_uml);

			if(this.m_loctype is IRNumericType | this.m_loctype is IREnumType)
				return new AHomeLocation(this.m_loctype, this.m_locationaddress, this.IsGlobalLocation, ida, fli, umv, this.m_numval, default(AReference), default(APtrValueMap));
			else if(this.m_loctype is IRReferenceType)
				return new AHomeLocation(this.m_loctype, this.m_locationaddress, this.IsGlobalLocation, ida, fli, umv, ZeroOne.Value.Zero, this.m_refval, default(APtrValueMap));
			else
				return new AHomeLocation(this.m_loctype, this.m_locationaddress, this.IsGlobalLocation, ida, fli, umv, ZeroOne.Value.Zero, default(AReference), this.m_ptrinfo);
		}

		public override string ToString()
		{
			string infos = "Home " + this.Address.ToString() + " ";
			if(this.m_loctype is IRNumericType | this.m_loctype is IREnumType)
				return infos + ZeroOne.ConvertValueToString(this.m_numval) + " " + this.ComputeGeneralInfoString();
			else if(this.m_loctype is IRReferenceType)
				return infos + this.m_refval.ToString() + " " + this.ComputeGeneralInfoString();
			else
				return infos + this.m_ptrinfo.ToString() + " " + this.ComputeGeneralInfoString();
		}

		/// <summary>
		/// Get the reference value in this home location.
		/// </summary>
		internal AReference ReferenceValue
		{
			get
			{
				Contract.Requires(this.LocationType is IRReferenceType);

				return this.m_refval;
			}
		}

		/// <summary>
		/// Get the pointer value in this home location.
		/// </summary>
		internal APtrValueMap PointerValue
		{
			get
			{
				Contract.Requires(this.LocationType is IRPtrType);

				return this.m_ptrinfo;
			}
		}

		internal override bool IsUniqueLocation()
		{ return true; }

		internal override void UpdateAsUniqueLocation()
		{ return; }

		/// <summary>
		/// Return true if this location is ok to strong update.
		/// </summary>
		private bool DoStrongUpdate(bool uniquetrgtloc)
		{
			return uniquetrgtloc;
		}

		internal void ClearDeadLocation()
		{
			if(this.m_loctype is IRNumericType | this.m_loctype is IREnumType)
				this.m_numval = ZeroOne.Value.Zero;
			else if(this.m_loctype is IRReferenceType)
				this.m_refval = AReference.CreateDefaultNullReference((IRReferenceType)this.LocationType);
			else if(this.m_loctype is IRPtrType)
				this.m_ptrinfo = APtrValueMap.MakeInitalPtrValueMapPtr();
			else
				this.m_ptrinfo = APtrValueMap.MakeInitalPtrValueMapComposite(this.m_loctype.TypeDescription.AllTerminalAccessPaths);
		}

		/// <summary>
		/// Simulate the read of a numeric value from the home location (through the name of the location)
		/// </summary>
		internal ZeroOne.Value ReadNumericFromViaName(int line)
		{
			Contract.Requires(this.LocationType is IRNumericType | this.LocationType is IREnumType);

			UseModInfo.MarkUMI(this.m_uml, this.MayBeInternalAlloc(), this.MayBeExternalAlloc(), true, false, line, IRBasicAccessPath.EmptyAccessPath);
			return this.m_numval;
		}

		/// <summary>
		/// Simulate the write of a numeric value to the home location (through the name of the location)
		/// </summary>
		internal void WriteNumericToViaName(ZeroOne.Value val, int line)
		{
			Contract.Requires(this.LocationType is IRNumericType | this.LocationType is IREnumType);

			UseModInfo.MarkUMI(this.m_uml, this.MayBeInternalAlloc(), this.MayBeExternalAlloc(), false, true, line, IRBasicAccessPath.EmptyAccessPath);
			this.m_numval = this.DoStrongUpdate(true) ? val : ZeroOne.Value.Unknown;
		}

		/// <summary>
		/// Simulate the read of a reference value from the home location (through the name of the location)
		/// </summary>
		internal AReference ReadReferenceFromViaName(int line)
		{
			Contract.Requires(this.LocationType is IRReferenceType);

			UseModInfo.MarkUMI(this.m_uml, this.MayBeInternalAlloc(), this.MayBeExternalAlloc(), true, false, line, IRBasicAccessPath.EmptyAccessPath);
			return this.m_refval;
		}

		/// <summary>
		/// Simulate the write of a reference value to the home location (through the name of the location)
		/// </summary>
		internal void WriteReferenceToViaName(AReference val, int line)
		{
			Contract.Requires(this.LocationType is IRReferenceType);
			Contract.Requires(!this.IsGlobalLocation);

			UseModInfo.MarkUMI(this.m_uml, this.MayBeInternalAlloc(), this.MayBeExternalAlloc(), false, true, line, IRBasicAccessPath.EmptyAccessPath);
			this.m_refval = val;
		}

		/// <summary>
		/// Simulate the read of a pointer value from the home location (through the name of the location)
		/// </summary>
		internal APtrValueMap ReadPointerFromViaName(int line)
		{
			Contract.Requires(this.LocationType is IRPtrType);
			
			UseModInfo.MarkUMI(this.m_uml, this.MayBeInternalAlloc(), this.MayBeExternalAlloc(), true, false, line, IRBasicAccessPath.EmptyAccessPath);
			return this.m_ptrinfo.ReadPtrValues(IRBasicAccessPath.EmptyAccessPath);
		}

		/// <summary>
		/// Simulate the write of a pointer value to the home location (through the name of the location)
		/// </summary>
		internal void WritePointerToViaName(APtrValueMap pval, int line)
		{
			Contract.Requires(this.LocationType is IRPtrType);

			UseModInfo.MarkUMI(this.m_uml, this.MayBeInternalAlloc(), this.MayBeExternalAlloc(), false, true, line, IRBasicAccessPath.EmptyAccessPath);
			this.m_ptrinfo = this.m_ptrinfo.WritePtrValues(pval, IRBasicAccessPath.EmptyAccessPath, this.DoStrongUpdate(true), true);
		}

		internal override Nullable<APtrValueMap> DoGeneralReadFromLocation(IRBasicAccessPath bap, int line)
		{
			Contract.Assert(!(this.m_loctype is IRReferenceType) & !(this.m_loctype is IRFunctionPointerType));

			if(this.m_loctype is IRNumericType | this.m_loctype is IREnumType)
			{
				Contract.Assert(bap == IRBasicAccessPath.EmptyAccessPath);

				UseModInfo.MarkUMI(this.m_uml, this.MayBeInternalAlloc(), this.MayBeExternalAlloc(), true, false, line, IRBasicAccessPath.EmptyAccessPath);
				return null;
			}
			else if(this.m_loctype is IRPtrType)
			{
				Contract.Assert(bap == IRBasicAccessPath.EmptyAccessPath);

				UseModInfo.MarkUMI(this.m_uml, this.MayBeInternalAlloc(), this.MayBeExternalAlloc(), true, false, line, IRBasicAccessPath.EmptyAccessPath);
				return this.m_ptrinfo.ReadPtrValues(IRBasicAccessPath.EmptyAccessPath);
			}
			else
			{
				if(bap == IRBasicAccessPath.EmptyAccessPath)
				{
					foreach(IRBasicAccessPath sbap in this.m_loctype.TypeDescription.AllTerminalAccessPaths)
						UseModInfo.MarkUMI(this.m_uml, this.MayBeInternalAlloc(), this.MayBeExternalAlloc(), true, false, line, sbap);

					return this.m_ptrinfo.ReadPtrValues(bap);
				}
				else if(bap.PathLast.FieldType is IRNumericType | bap.PathLast.FieldType is IREnumType)
				{
					UseModInfo.MarkUMI(this.m_uml, this.MayBeInternalAlloc(), this.MayBeExternalAlloc(), true, false, line, bap);
					return null;
				}
				else if(bap.PathLast.FieldType is IRPtrType)
				{
					UseModInfo.MarkUMI(this.m_uml, this.MayBeInternalAlloc(), this.MayBeExternalAlloc(), true, false, line, bap);

					return this.m_ptrinfo.ReadPtrValues(bap);
				}
				else
				{
					foreach(IRBasicAccessPath sbap in bap.PathLast.FieldType.TypeDescription.AllTerminalAccessPaths)
					{
						IRBasicAccessPath fsbap = GlobalAnalysisState.TProg.GetAccessPathExtensionPost_WPath(bap, sbap);
						UseModInfo.MarkUMI(this.m_uml, this.MayBeInternalAlloc(), this.MayBeExternalAlloc(), true, false, line, fsbap);
					}

					return this.m_ptrinfo.ReadPtrValues(bap);
				}
			}
		}

		internal override void DoGeneralWriteToLocation(IRBasicAccessPath bap, APtrValueMap pvals, bool isuniquereftrgt, int line)
		{
			Contract.Assert(!(this.m_loctype is IRReferenceType) & !(this.m_loctype is IRFunctionPointerType));

			if(this.m_loctype is IRNumericType | this.m_loctype is IREnumType)
			{
				Contract.Assert(bap == IRBasicAccessPath.EmptyAccessPath);

				UseModInfo.MarkUMI(this.m_uml, this.MayBeInternalAlloc(), this.MayBeExternalAlloc(), false, true, line, IRBasicAccessPath.EmptyAccessPath);
			}
			else if(this.m_loctype is IRPtrType)
			{
				Contract.Assert(bap == IRBasicAccessPath.EmptyAccessPath);

				UseModInfo.MarkUMI(this.m_uml, this.MayBeInternalAlloc(), this.MayBeExternalAlloc(), false, true, line, IRBasicAccessPath.EmptyAccessPath);
				this.m_ptrinfo = this.m_ptrinfo.WritePtrValues(pvals, bap, this.DoStrongUpdate(isuniquereftrgt), true);
			}
			else
			{
				if(bap == IRBasicAccessPath.EmptyAccessPath)
				{
					foreach(IRBasicAccessPath sbap in this.m_loctype.TypeDescription.AllTerminalAccessPaths)
						UseModInfo.MarkUMI(this.m_uml, this.MayBeInternalAlloc(), this.MayBeExternalAlloc(), false, true, line, sbap);

					this.m_ptrinfo = this.m_ptrinfo.WritePtrValues(pvals, bap, this.DoStrongUpdate(isuniquereftrgt), true);
				}
				else if(bap.PathLast.FieldType is IRNumericType | bap.PathLast.FieldType is IREnumType)
				{
					UseModInfo.MarkUMI(this.m_uml, this.MayBeInternalAlloc(), this.MayBeExternalAlloc(), false, true, line, bap);
				}
				else if(bap.PathLast.FieldType is IRPtrType)
				{
					UseModInfo.MarkUMI(this.m_uml, this.MayBeInternalAlloc(), this.MayBeExternalAlloc(), false, true, line, bap);

					this.m_ptrinfo = this.m_ptrinfo.WritePtrValues(pvals, bap, this.DoStrongUpdate(isuniquereftrgt), true);
				}
				else
				{
					foreach(IRBasicAccessPath sbap in bap.PathLast.FieldType.TypeDescription.AllTerminalAccessPaths)
					{
						IRBasicAccessPath fsbap = GlobalAnalysisState.TProg.GetAccessPathExtensionPost_WPath(bap, sbap);
						UseModInfo.MarkUMI(this.m_uml, this.MayBeInternalAlloc(), this.MayBeExternalAlloc(), false, true, line, fsbap);
					}

					this.m_ptrinfo = this.m_ptrinfo.WritePtrValues(pvals, bap, this.DoStrongUpdate(isuniquereftrgt), true);
				}
			}
		}

		internal override IEnumerator<ATrgtEnum> GetTargetEnum()
		{
			if(this.m_loctype is IRNumericType | this.m_loctype is IREnumType | this.m_loctype is IRFunctionPointerType)
				return new DummyTargetEnum();
			else if(this.m_loctype is IRReferenceType)
				return this.m_refval.GetATrgtEnumerator();
			else
				return this.m_ptrinfo.GetATrgtEnumerator();
		}

		/// <summary>
		/// The enumerator for when this location stores a numeric value
		/// </summary>
		internal sealed class DummyTargetEnum : IEnumerator<ATrgtEnum>
		{
			internal DummyTargetEnum()
			{ ;}

			public ATrgtEnum Current
			{ get { throw new InvalidOperationException(); } }

			public void Dispose()
			{ ;}

			object System.Collections.IEnumerator.Current
			{ get { throw new InvalidOperationException(); } }

			public bool MoveNext()
			{ return false; }

			public void Reset()
			{ ;}
		}

		internal override int TotalTargetCount()
		{
			if(this.m_loctype is IRNumericType | this.m_loctype is IREnumType | this.m_loctype is IRFunctionPointerType)
				return 0;
			else if(this.m_loctype is IRReferenceType)
				return this.m_refval.RTargetCount;
			else
				return this.m_ptrinfo.PTargetCount;
		}

		/// <summary>
		/// Resolve the reference for the given trgtneum
		/// </summary>
		internal APossibleReferenceTarget ResolveRefFromEnum(ATrgtEnum tenum)
		{
			Contract.Assert(this.LocationType is IRReferenceType);

			return this.m_refval.ResolveRefFromEnum(tenum);
		}

		/// <summary>
		/// Perform Sanity check on node state.
		/// </summary>
		internal override void CheckNodeOK(List<ALocation> memory)
		{
			base.CheckNodeOK(memory);

			HashSet<APossibleReferenceTarget> checksetr = new HashSet<APossibleReferenceTarget>();

			IEnumerator<ATrgtEnum> trgtenum = this.GetTargetEnum();
			while(trgtenum.MoveNext())
			{
				ATrgtEnum tte = trgtenum.Current;

				if(tte.TrgtAddress < 0 || tte.TrgtAddress >= memory.Count)
					DebugReport.ReportError("We have an out of bounds edge reference.");
				
				ALocation tn = memory[tte.TrgtAddress];
				IRType tlt = tn.LocationType;

				if(this.m_identities.Length > 1)
					DebugReport.ReportError("How did these get merged?");

				if(this.m_loctype is IRReferenceType)
				{
					APossibleReferenceTarget rrt = this.ResolveRefFromEnum(tte);

					if(rrt.TrgtOffset == IRBasicAccessPath.EmptyAccessPath)
					{
						if(GlobalAnalysisState.TProg.TypeTable.InternReferenceTypeFor(tlt) != this.m_loctype)
							DebugReport.ReportError("The pointer type stored to is not compatible with the type reported in the target node");
					}

					if(checksetr.Contains(rrt))
						DebugReport.ReportError("Has multi edges with same offset!!!!");
					else
						checksetr.Add(rrt);
				}
				else
				{
					APossiblePointerTarget ppt = this.ResolvePtrFromEnum(tte);

					if(!ppt.IsInjective)
						DebugReport.ReportError("We have a non-injective pointers in an eval stack location??");
				}
			}
		}

		protected override bool EqualALocationSubclass(ALocation ol)
		{
			if(!(ol is AHomeLocation))
				return false;

			AHomeLocation ohl = (AHomeLocation)ol;
			Contract.Assert(this.m_loctype == ohl.m_loctype, "This needs to be checked first!!");

			if(this.IsGlobalLocation != ohl.IsGlobalLocation)
				return false;

			if(this.m_loctype is IRNumericType | this.m_loctype is IREnumType)
				return ZeroOne.EquivValues(this.m_numval, ohl.m_numval);
			else if(this.m_loctype is IRReferenceType)
				return AReference.DomainEqualIgnoreTargets(this.m_refval, ohl.m_refval);
			else
				return APtrValueMap.DomainEqualIgnoreTargets(this.m_ptrinfo, ohl.m_ptrinfo);
		}

		internal override void DeletePossibleTargets(HashSet<int> deleteset)
		{
			if(this.m_loctype is IRNumericType | this.m_loctype is IREnumType | this.m_loctype is IRFunctionPointerType)
				return;
			else if(this.m_loctype is IRReferenceType)
				this.m_refval = this.m_refval.DeletePossibleTargets(deleteset);
			else
				this.m_ptrinfo = this.m_ptrinfo.DeletePossibleTargets(deleteset);
		}

		internal override void MoveWithUpdatedAddress_ISOMapping(Dictionary<int, int> addrReMap)
		{
			this.m_locationaddress = addrReMap[this.m_locationaddress];

			if(this.m_loctype is IRNumericType | this.m_loctype is IREnumType | this.m_loctype is IRFunctionPointerType)
			{ ;}
			else if(this.m_loctype is IRReferenceType)
				this.m_refval = this.m_refval.UpdateAddresses_ISOMapping(addrReMap);
			else
				this.m_ptrinfo = this.m_ptrinfo.UpdateAddresses_ISOMapping(addrReMap);
		}

		internal override void MoveWithUpdatedAddresses_MayMergeButNoNewInj(Dictionary<int, int> addrReMap)
		{
			this.m_locationaddress = addrReMap[this.m_locationaddress];

			if(this.m_loctype is IRNumericType | this.m_loctype is IREnumType | this.m_loctype is IRFunctionPointerType)
			{ ;}
			else if(this.m_loctype is IRReferenceType)
				this.m_refval = this.m_refval.UpdatedAddresses_MayMerge(addrReMap);
			else
				this.m_ptrinfo = this.m_ptrinfo.UpdatedAddresses_MayMergeButNoNewInj(addrReMap, true);
		}

		protected override ALocation JoinLocationsFromDifferentContextsSubclass(ALocation ol, int[] residentities, EscapeSiteInfo[] resfreshlocs, List<UseModInfo> resuml)
		{
			Contract.Assert(ol is AHomeLocation);
			Contract.Assert(this.m_loctype == ((AHomeLocation)ol).m_loctype);
			Contract.Assert(this.m_locationaddress == ((AHomeLocation)ol).m_locationaddress);

			if(this.m_loctype is IRNumericType | this.m_loctype is IREnumType)
			{
				ZeroOne.Value vv = ZeroOne.JoinValues(this.m_numval, ((AHomeLocation)ol).m_numval);
				return new AHomeLocation(this.m_loctype, this.m_locationaddress, this.IsGlobalLocation, residentities, resfreshlocs, resuml, vv, default(AReference), default(APtrValueMap));
			}
			else if(this.m_loctype is IRReferenceType)
			{
				AReference rval = this.m_refval.MergeOtherReferenceTargetWith(((AHomeLocation)ol).m_refval);
				return new AHomeLocation(this.m_loctype, this.m_locationaddress, this.IsGlobalLocation, residentities, resfreshlocs, resuml, ZeroOne.Value.Zero, rval, default(APtrValueMap));
			}
			else
			{
				APtrValueMap ppa = APtrValueMap.MergeAPtrMaps(this.m_ptrinfo, ((AHomeLocation)ol).m_ptrinfo, true, true);
				return new AHomeLocation(this.m_loctype, this.m_locationaddress, this.IsGlobalLocation, residentities, resfreshlocs, resuml, ZeroOne.Value.Zero, default(AReference), ppa);
			}
		}

		protected override ALocation JoinLocationSetFromSameContextSubclass(List<ALocation> lset, int resaddress, int[] residentities, EscapeSiteInfo[] resfreshlocs, List<UseModInfo> resuml, Dictionary<int, int> addrReMap)
		{
			Nullable<ZeroOne.Value> vv = null;
			Nullable<APtrValueMap> baplm = null;
			Nullable<AReference> avl = null;
			
			if(this.m_loctype is IRNumericType | this.m_loctype is IREnumType)
			{
				foreach(ALocation ol in lset)
				{
					Contract.Assert(ol is AHomeLocation);
					if(!vv.HasValue)
						vv = ((AHomeLocation)ol).m_numval;
					else
						vv = ZeroOne.JoinValues(vv.Value, ((AHomeLocation)ol).m_numval);
				}
			}
			else if(this.m_loctype is IRReferenceType)
			{
				foreach(ALocation ol in lset)
				{
					Contract.Assert(ol is AHomeLocation);
					if(!avl.HasValue)
						avl = ((AHomeLocation)ol).m_refval;
					else
						avl = avl.Value.MergeOtherReferenceTargetWith(((AHomeLocation)ol).m_refval);
				}

				avl = avl.Value.UpdatedAddresses_MayMerge(addrReMap);
			}
			else
			{
				foreach(ALocation ol in lset)
				{
					Contract.Assert(ol is AHomeLocation);
					if(!baplm.HasValue)
						baplm = ((AHomeLocation)ol).m_ptrinfo;
					else
						baplm = APtrValueMap.MergeAPtrMaps(baplm.Value, ((AHomeLocation)ol).m_ptrinfo, false, true);
				}

				baplm = baplm.Value.UpdatedAddresses_MayMergeButNoNewInj(addrReMap, true);
			}

			ZeroOne.Value fvv = vv.HasValue ? vv.Value : ZeroOne.Value.Zero;
			AReference favl = avl.HasValue ? avl.Value : default(AReference);
			APtrValueMap fbaplm = baplm.HasValue ? baplm.Value : default(APtrValueMap);
			
			return new AHomeLocation(this.m_loctype, resaddress, this.IsGlobalLocation, residentities, resfreshlocs, resuml, fvv, favl, fbaplm);
		}

		internal override void ReplaceAssociatedCutpointsAsNeeded(Dictionary<int, int> addressToCPIDMap, HashSet<int> idsofinterest)
		{
			if(this.m_loctype is IRNumericType | this.m_loctype is IREnumType | this.m_loctype is IRFunctionPointerType)
				return;
			else if(this.m_loctype is IRReferenceType)
				this.m_refval = this.m_refval.ReplaceAssociatedCutpointsAsNeeded(addressToCPIDMap);
			else
			{
				if(this.m_ptrinfo.HasTargetInSet(idsofinterest))
					this.m_ptrinfo = this.m_ptrinfo.ReplaceAssociatedCutpointsAsNeeded(addressToCPIDMap);
			}
		}

		internal override void UpdateOutEdgesAfterCutpointEdgeExpand(Dictionary<int, int[]> cpidToAddressMap, HashSet<int> idsofinterest)
		{
			if(this.m_loctype is IRNumericType | this.m_loctype is IREnumType | this.m_loctype is IRFunctionPointerType)
				return;
			else if(this.m_loctype is IRReferenceType)
				this.m_refval = this.m_refval.UpdateOutEdgesAfterCutpointEdgeExpand(cpidToAddressMap);
			else
			{
				if(this.m_ptrinfo.HasTargetInSet(idsofinterest))
					this.m_ptrinfo = this.m_ptrinfo.UpdateOutEdgesAfterCutpointEdgeExpand(cpidToAddressMap, true);
			}
		}
	}
}
